
#ifndef IAPPLICATION_H
#define IAPPLICATION_H

#include "common.hpp"

#include <vector>

/////////////
// General //
/////////////

// Mappings

#include <map>

template<class Key, class Map>
class IMapping {

protected:
	std::map<Key, Map> mapping;

public:
	Map operator[](Key k) {
		return mapping[k];
	}
};

// Exceptions

#include <string>

class IException {
	
protected:
	const char* exc_id;
	const char *infotxt;
	const char *file;
	const int line;

public:
	IException(const char *f, int l, const char* i, const char *id) :
		exc_id(id), infotxt(i),  file(f), line(l)  { };

	std::string info() const {
		return std::string(exc_id) + ": " + std::string(infotxt);
	}

	std::string location() const {
		return std::string(file) + ":" + std::string(_qtwi_to_string<int>(line));
	}
};

class INotImplementedYet : public IException {

public:
	INotImplementedYet(const char *id, const char* info) : IException("", 0, info, id) { }
};

///////////
// Timer //
///////////

class ITimerHandler
{
public:
	void *data;

public:
	ITimerHandler(void *d = NULL) : data(NULL) { }
	// Overwritten by user derivations
	virtual void timeout() { };
};

class ITimer
{
	
};


////////////
// Colors //
////////////


class IColor {
	
public:
	enum Color {
		Yellow,
		Green,
		Blue,
		Grey,
	};
};

/////////////
// Widgets //
/////////////

class IWidget {
	
public:
	
	virtual void show() = 0;
	virtual void hide() { }
	virtual void refresh() { }
	virtual void enable() { }
	virtual void disable() { }
	virtual void move(int, int) { }
	virtual int getWidth() const { return 0; }
	virtual void resize(int, int) { }
	virtual void setBgColor(IColor::Color) { }
	virtual void setFgColor(IColor::Color) { }
};


/////////////
// Actions //
/////////////

class IActionHandler {

public:

	// Action to be taken; overwrite in derived application action handlers
	virtual void handler(IWidget &) = 0;

	virtual void operator() (IWidget& sender) {
		handler(sender);
	}

};

class IAction {

public:

	enum Action {
		CLICK,
		MOD,
		SELECT,
		TIME,
		CLOSE
	};

	// For Qt:
	// 	action = signal
	// 	actionHandler = slot
	// 	actionReceiver = object emitting signal
	//
	// For TNW++:
	// 	action = callback constant
	// 	actionHandler = callback function
	// 	actionReceiver = object receiving action
	
	virtual void registerAction(IWidget &actionReceiver, Action action, IActionHandler *ah) = 0;
};


/////////////////
// Application //
/////////////////

class IWidget;
class IAction;

class IApplication {
	
public:
	class_iexception(IMainWidgetNotSet, "main widget not set; use IApplication::setMainWidget()")
	
	virtual int exec() = 0;

	virtual void registerAction(IWidget &actionReceiver, IAction::Action a, IActionHandler *) = 0;
	
	virtual void registerTimer(ITimerHandler *timer, IWidget *parent, time_t interval) = 0;

private:
	std::vector<IWidget*> affiliated_widgets;

public:
	/*
	 * Affiliated widgets are mainly used for registering ananomyous IMonologues that are to be
	 * displayed for a certain period of time. This way they are regisatered in some way,
	 * don't have to be named, don't pass out of scope, and can be cleaned up using repudiateWidgets().
	 * This should be done frequently.
	 */

	void affiliateWidget(IWidget &w) {
		affiliated_widgets.push_back(&w);
	}

	void repuidateWidgets() {

		for(std::vector<IWidget*>::const_iterator i = affiliated_widgets.begin(); i != affiliated_widgets.end(); i++)
			delete *i;
		
		affiliated_widgets.clear();
	}
};

#endif
